/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
/**
 * \file
 * \brief Example file for using the binbag::CBinBag container.
 * \author Antti Maula <antti.maula@tkk.fi>
 *
 */
#include "owndebug.h"
#include "binbag.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

int main(int argc, char *argv[])
{
  int result = 0;
  int repeat = 1;
  int silent = 0;

  // Test for params
  if (argc > 1) {
    repeat = atoi(argv[1]);
    printf("Using %d repeat rounds\n", repeat);
  }
  if (argc > 2) {
    silent = 1;
  }

  // Init debug facility & set level to 10
  debugInit();
  debugSetGlobalDebugLvl(silent?0:10);

  // Create BinBag instance
  char strs[][64] = { "aaaaaaaaaa",
		      "bbbbbbbbbb",
		      "cccccccccc",
		      "dddddddddd",
		      "eeeeeeeeee" };

  do {
    gim::binbag::CBinBag bb;
    
    // Test binary insertion
    for(int i = 0; i < 5; ++i) {
      if (!silent) printf("Inserting blob: '%s'\n", strs[i]);
      bb.AddBinary(i, strs[i], strlen(strs[i])+1);
    }

    if (!silent) printf("Trying to insert oversized element.\n");
    if (bb.AddBinary(100, "foo", 16777217) != NULL) {
      printf("Should have failed!\n");
      abort();
    }


    if (!silent) printf("Testing Blob iteration:\n");
    // Test iteration through elements
    const gim::binbag::TBinBlob *blob;
    bb.Rewind();
  
    while((blob = bb.GetNextBinary())) {
      if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                          blob->type, blob->size, blob->data);
    }


    // Testing Buffer reading & rewinding
    const char *testbuffer = bb.GetBuffer();
    int testbufferlen = bb.GetBufferSize();

    gim::binbag::CBinBag bb2;
    if (bb2.Decode(testbuffer, testbufferlen) == true) {
      if (!silent) printf("Testing bb2, which was Decoded from buffer returned by bb:\n");
      while((blob = bb2.GetNextBinary())) {
        if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                            blob->type, blob->size, blob->data);
      }
      bb2.Rewind();
      if (!silent) printf("Test bb2 again after Rewind:\n");
      while((blob = bb2.GetNextBinary())) {
        if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                            blob->type, blob->size, blob->data);
      }

    
    } else {
      if (!silent) printf("Failed to Decode testbuffer!");

    }

    // Testing Copying buffer and rewinding & reading
    gim::binbag::CBinBag bb3(bb2);
    bb3.Rewind();
    if (!silent) printf("Test bb3 after copying from bb2:\n");
    while((blob = bb3.GetNextBinary())) {
      if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                          blob->type, blob->size, blob->data);
    }

    // Testing Trimming
    if (!silent) printf("Testing TrimBuffer() feature:\n");
    if (!silent) printf("Reserved BufferSize of container 'bb3' after operations: %d bytes\n", bb3.GetBufferReservedSize());
    bb3.TrimBuffer();
    if (!silent) printf("Reserved BufferSize of container 'bb3' after TrimBuffer(): %d bytes\n", bb3.GetBufferReservedSize());


    // Testing new feature; supporting Rewind between Adds
    gim::binbag::CBinBag bb4;
    if (!silent) printf("Adding 5 elements to container bb4\n");
    for(int i = 0; i < 5; ++i) {
      if (!silent) printf("bb4: Inserting blob: '%s'\n", strs[i]);
      bb4.AddBinary(i, strs[i], strlen(strs[i])+1);
    }
    bb4.Rewind();
    if (!silent) printf("Test Gets to bb4 after Rewind:\n");
    while((blob = bb4.GetNextBinary())) {
      if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                          blob->type, blob->size, blob->data);
    }
    if (!silent) printf("Inserting again after Rewind() and Get's.\n");
    for(int i = 0; i < 5; ++i) {
      if (!silent) printf("bb4: Inserting blob: '%s'\n", strs[i]);
      bb4.AddBinary(i, strs[i], strlen(strs[i])+1);
    }
    bb4.Rewind();
    if (!silent) printf("Test Gets to bb4 after Rewind and 2nd add round.\n");
    while((blob = bb4.GetNextBinary())) {
      if (!silent) printf("Got element, type %d, %d bytes payload, payload is: '%s'\n", 
                          blob->type, blob->size, blob->data);
    }
    
    // Testing new feature; Compress!
    gim::binbag::CBinBag bb5;
    int elemcount = 1000;
    if (!silent) printf("Adding %d elements to container bb5\n", elemcount);
    for(int i = 0; i < elemcount; ++i) {
      assert ( bb5.AddBinary(i%5, strs[i%5], strlen(strs[i%5])+1) );
    }
    
    // Prinnt uncomp size.
    printf("Uncompressed Size of bb5 is %u bytes\n", bb5.GetBufferSize());

    // Compress!
    assert( bb5.CompressZLIB() == true );

    // Check size of compressed
    printf("Compressed Size of bb5 is %u bytes\n", bb5.GetBufferSize());

    gim::binbag::CBinBag bb6;
    if (bb6.Decode(bb5.GetBuffer(), bb5.GetBufferSize()) == true) {
      printf("Uncompressed size of bb6 is %u bytes\n", bb6.GetBufferSize());
          
      if (!silent) printf("Testing bb6, which was Decoded from compressed buffer returned by bb5:\n");
      int ecount = 0;
      while((blob = bb6.GetNextBinary())) {
        ++ecount;
      }
      assert(ecount == elemcount);
      
    } else {
      printf("Failed to Decode testbuffer!");
      
    }
  } while(--repeat);
  


  printf("Done. Exit.\n");
  // Exit.
  return result;
}

//*****************************************************************************
